package com.hnx.admin.aurora.jwt.config;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.hnx.admin.aurora.jwt.api.JwtAPI;
import com.hnx.admin.aurora.jwt.core.JwtProperties;
import com.hnx.admin.aurora.redis.RedisCache;
import com.hnx.admin.aurora.web.exception.JwtVerificationException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/*
创建人： 倔强的头发
创建时间：2025/6/15
功能描述:

*/
@Component
@RequiredArgsConstructor
public class JwtUtil implements JwtAPI {
    private final JwtProperties jwtProperties;
    private final RedisCache redisCache;
    private final static long MINUTE = 1000 * 60;
    private Set<String> blackList = new HashSet<>();

    private Algorithm getAlgorithm() {
        if (StringUtils.hasText(jwtProperties.getSecret())) {
            return Algorithm.HMAC256(jwtProperties.getSecret());
        }
        throw new RuntimeException("请配置token中的secret属性值");
    }

    /**
     * 从token中获取claims
     */
    public Map<String, String> getClaimsFromToken(String token) {
        DecodedJWT decodedJWT = verifyToken(token);
        Map<String, String> claims = new HashMap<>();
        decodedJWT.getClaims().forEach((key, claim) -> claims.put(key, claim.asString()));

        return claims;
    }

    /*
     * 构建token
     * */
    public String createToken(Map<String, String> map) {
        return buildToken(map);
    }

    private String buildToken(Map<String, String> map) {
        Date now = new Date();
        Date expireTime = new Date(now.getTime() + jwtProperties.getExpireTime() * MINUTE);
        try {
            JWTCreator.Builder builder = JWT.create()
                    .withIssuer(jwtProperties.getIssuer())
                    .withIssuedAt(now)
                    .withExpiresAt(expireTime);
            if (Objects.nonNull(map)) {
                map.forEach((k, v) -> {
                    builder.withClaim(k, v);
                });
            }
            return builder.sign(getAlgorithm());
        } catch (Exception e) {
            throw new JwtVerificationException("创建token异常");
        }
    }

    public DecodedJWT verifyToken(String token) {
        String bearer_token = token.replace("Bearer ", "");
        try {
            JWTVerifier jwt = JWT.require(getAlgorithm())
                    .withIssuer(jwtProperties.getIssuer())
                    .acceptLeeway(jwtProperties.getClockSkew()).build();//生成验证对象
            DecodedJWT verify = jwt.verify(bearer_token);
            return verify;
        } catch (AlgorithmMismatchException ex) {
            throw new JwtVerificationException("算法不匹配");
        } catch (SignatureVerificationException e) {
            throw new JwtVerificationException("签名验证失败");
        } catch (TokenExpiredException e) {
            throw new JwtVerificationException("token已过期");
        } catch (Exception e) {
            throw new JwtVerificationException(e.getMessage());
        }
    }

    /*
     * 解析token
     * */
    public DecodedJWT parseToken(String token) {
        return JWT.decode(token);
    }

    public <T> void validToken(String token,T user) {
        if (isRefresh(token)) {
            DecodedJWT jwt = verifyToken(token);
            String uuid = jwt.getClaim(LOGIN_USER_KEY).asString();
            if (StringUtils.hasText(uuid)) {
                setRedisCache(uuid, user);
                Map<String, String> map = new HashMap<>();
                map.put(LOGIN_USER_KEY, uuid);
                buildToken(map);
            } else {
                throw new JwtVerificationException("token已失效，请重新登录");
            }
        }
    }

    /**
     * 检查token是否需要刷新
     * 判断条件：token有效时间小于5分钟
     */
    public boolean isRefresh(String token) {
        DecodedJWT jwt = verifyToken(token);
        long time = jwt.getExpiresAt().getTime() - System.currentTimeMillis();
        return time <= TimeUnit.MINUTES.toMillis(5);
    }

    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    public String getToken(HttpServletRequest request) {
        String token = request.getHeader(jwtProperties.getHeader());
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(token) && token.startsWith(TOKEN_PREFIX)) {
            token = token.replace(TOKEN_PREFIX, "");
        }
        return token;
    }

    public <T> void setRedisCache(String uuid, T value) {
        String key = getTokenKey(uuid);
        if (Objects.nonNull(value)) {
            redisCache.setCacheObject(key, value, (int) jwtProperties.getExpireTime(), TimeUnit.MINUTES);
        }
    }

    public String getTokenKey(String uuid) {
        return LOGIN_TOKEN_KEY + uuid;
    }

    public String getUserKey(HttpServletRequest request) {
        if (Objects.nonNull(request)) {
            String token = getToken(request);
            if (org.springframework.util.StringUtils.hasText(token)) {
                DecodedJWT jwt = parseToken(token);
                String uuid = jwt.getClaim(LOGIN_USER_KEY).asString();
                return getTokenKey(uuid);
            }
        }
        return null;
    }
}
